package edu.weseda.simulator;

import static edu.weseda.simulator.Constant.RESOURCE_PATH;

import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.nnet.RBFNetwork;
import org.neuroph.nnet.learning.RBFLearning;

import Jama.Matrix;


public class RBF {

	@SuppressWarnings("unchecked")
	public static RBFNetwork trainRBFNetwork(Matrix trainingInput, Matrix trainingOutput){
		int neuralNum = trainingInput.getColumnDimension();
		int inputNum = trainingInput.getRowDimension();
		int outputNum = trainingOutput.getRowDimension();
		if(neuralNum != trainingOutput.getColumnDimension() || inputNum != 2 || outputNum != 1){
			throw new RuntimeException("input and output don't match!");
		}
		RBFNetwork net = new RBFNetwork(inputNum, neuralNum, outputNum);
		DataSet trainingSet = new DataSet(2,1);
		for(int i=0;i<neuralNum;i++){
			double[] input = new double[]{trainingInput.get(0, i), trainingInput.get(1, i)};
			double[] output = new double[]{trainingOutput.get(0, i)};
			trainingSet.addRow(input, output);
		}
		RBFLearning rule = new RBFLearning();
		rule.setMaxError(0.00001);
		net.setLearningRule(rule);
		net.learn(trainingSet);
		return net;
	}
	
	// get multiple output from multiple input
	public static Matrix simulate(RBFNetwork net, Matrix inputMatrix){
		int inputNum = inputMatrix.getRowDimension();
		if(inputNum != 2){
			throw new RuntimeException("invalid input, Please check!");
		}
		int columnDimension = inputMatrix.getColumnDimension();
		Matrix outputMatrix = new Matrix(1,columnDimension);
		for(int i=0;i<columnDimension;i++){
			double[] input = new double[]{inputMatrix.get(0, i),inputMatrix.get(1, i)};
			net.setInput(input);
			net.calculate();
			double[] output = net.getOutput();
			outputMatrix.set(0, i, output[0]);
		}
		return outputMatrix;
	}
	
	public static void saveNetwork(RBFNetwork net, String fileName){
		net.save(RESOURCE_PATH + fileName);
	}
	
	@SuppressWarnings("rawtypes")
	public static NeuralNetwork loadNetwork(String fileName){
		return RBFNetwork.createFromFile(RESOURCE_PATH + fileName);		
	}
	
}
